import { VantComponent } from '../common/component'
import { touch } from '../mixins/touch'
import { canIUseModel } from '../common/version'
import { getRect, addUnit, nextTick, addNumber, clamp } from '../common/utils'
const DRAG_STATUS = {
  START: 'start',
  MOVING: 'moving',
  END: 'end',
}
VantComponent({
  mixins: [touch],
  props: {
    range: Boolean,
    disabled: Boolean,
    useButtonSlot: Boolean,
    activeColor: String,
    inactiveColor: String,
    max: {
      type: Number,
      value: 100,
    },
    min: {
      type: Number,
      value: 0,
    },
    step: {
      type: Number,
      value: 1,
    },
    value: {
      type: null,
      value: 0,
      observer(val) {
        if (val !== this.value) {
          this.updateValue(val)
        }
      },
    },
    vertical: Boolean,
    barHeight: null,
  },
  created() {
    this.updateValue(this.data.value)
  },
  methods: {
    onTouchStart(event) {
      if (this.data.disabled) return
      const { index } = event.currentTarget.dataset
      if (typeof index === 'number') {
        this.buttonIndex = index
      }
      this.touchStart(event)
      this.startValue = this.format(this.value)
      this.newValue = this.value
      if (this.isRange(this.newValue)) {
        this.startValue = this.newValue.map((val) => this.format(val))
      } else {
        this.startValue = this.format(this.newValue)
      }
      this.dragStatus = DRAG_STATUS.START
    },
    onTouchMove(event) {
      if (this.data.disabled) return
      if (this.dragStatus === DRAG_STATUS.START) {
        this.$emit('drag-start')
      }
      this.touchMove(event)
      this.dragStatus = DRAG_STATUS.MOVING
      getRect(this, '.van-slider').then((rect) => {
        const { vertical } = this.data
        const delta = vertical ? this.deltaY : this.deltaX
        const total = vertical ? rect.height : rect.width
        const diff = (delta / total) * this.getRange()
        if (this.isRange(this.startValue)) {
          this.newValue[this.buttonIndex] = this.startValue[this.buttonIndex] + diff
        } else {
          this.newValue = this.startValue + diff
        }
        this.updateValue(this.newValue, false, true)
      })
    },
    onTouchEnd() {
      if (this.data.disabled) return
      if (this.dragStatus === DRAG_STATUS.MOVING) {
        this.dragStatus = DRAG_STATUS.END
        nextTick(() => {
          this.updateValue(this.newValue, true)
          this.$emit('drag-end')
        })
      }
    },
    onClick(event) {
      if (this.data.disabled) return
      const { min } = this.data
      getRect(this, '.van-slider').then((rect) => {
        const { vertical } = this.data
        const touch = event.touches[0]
        const delta = vertical ? touch.clientY - rect.top : touch.clientX - rect.left
        const total = vertical ? rect.height : rect.width
        const value = Number(min) + (delta / total) * this.getRange()
        if (this.isRange(this.value)) {
          const [left, right] = this.value
          const middle = (left + right) / 2
          if (value <= middle) {
            this.updateValue([value, right], true)
          } else {
            this.updateValue([left, value], true)
          }
        } else {
          this.updateValue(value, true)
        }
      })
    },
    isRange(val) {
      const { range } = this.data
      return range && Array.isArray(val)
    },
    handleOverlap(value) {
      if (value[0] > value[1]) {
        return value.slice(0).reverse()
      }
      return value
    },
    updateValue(value, end, drag) {
      if (this.isRange(value)) {
        value = this.handleOverlap(value).map((val) => this.format(val))
      } else {
        value = this.format(value)
      }
      this.value = value
      const { vertical } = this.data
      const mainAxis = vertical ? 'height' : 'width'
      this.setData({
        wrapperStyle: `
          background: ${this.data.inactiveColor || ''};
          ${vertical ? 'width' : 'height'}: ${addUnit(this.data.barHeight) || ''};
        `,
        barStyle: `
          ${mainAxis}: ${this.calcMainAxis()};
          left: ${vertical ? 0 : this.calcOffset()};
          top: ${vertical ? this.calcOffset() : 0};
          ${drag ? 'transition: none;' : ''}
        `,
      })
      if (drag) {
        this.$emit('drag', { value })
      }
      if (end) {
        this.$emit('change', value)
      }
      if ((drag || end) && canIUseModel()) {
        this.setData({ value })
      }
    },
    getScope() {
      return Number(this.data.max) - Number(this.data.min)
    },
    getRange() {
      const { max, min } = this.data
      return max - min
    },
    getOffsetWidth(current, min) {
      const scope = this.getScope()
      // 避免最小值小于最小step时出现负数情况
      return `${Math.max(((current - min) * 100) / scope, 0)}%`
    },
    // 计算选中条的长度百分比
    calcMainAxis() {
      const { value } = this
      const { min } = this.data
      if (this.isRange(value)) {
        return this.getOffsetWidth(value[1], value[0])
      }
      return this.getOffsetWidth(value, Number(min))
    },
    // 计算选中条的开始位置的偏移量
    calcOffset() {
      const { value } = this
      const { min } = this.data
      const scope = this.getScope()
      if (this.isRange(value)) {
        return `${((value[0] - Number(min)) * 100) / scope}%`
      }
      return '0%'
    },
    format(value) {
      const min = +this.data.min
      const max = +this.data.max
      const step = +this.data.step
      value = clamp(value, min, max)
      const diff = Math.round((value - min) / step) * step
      return addNumber(min, diff)
    },
  },
})
